Breakpoints are a useful feature of software debuggers that cause program execution to be paused under certain circumstances. Typically, breakpoints specify particular locations in an application or program code where, if control is reached, execution is paused. Modern central processing units (CPUs) also offer ability to watch a program's access to particular memory locations, for example either read/write access or instruction execution. A register in such a CPU may be set to a memory address location. Program execution will pause whenever it accesses the memory address specified in the register. Every CPU will provide few such registers. While debugging a multi-threaded program, a debugger may wish to debug only some threads execution and not others. This is conveniently accomplished by using registers defined above. Every thread will have some execution context associated with it. This context includes the value all the registers used by it, which can include the registers. By setting the value of the register in one thread's context and not in other thread's, per-thread debugging is enabled.
At times, it may be necessary to pause program execution as the program is about to exit a function or when a return to caller is encountered. Accomplishing this using breakpoints requires knowledge of the exit points in a function. While it's sometimes easy to find location (address) of a function entry point, finding all locations (addresses) from where a function can exit is non-trivial. This would require decoding all instructions comprising the function and finding out where the ‘return’ instructions are present, which can be time consuming and compromise on efficiency, especially when large function bodies are considered. Also in case of multi-threaded applications and in a system with multiple CPU's, sometimes programmers tend to debug only a particular thread of that application and not all threads. Consequently programmers may require the function exit to be traced only when that particular thread being debugged hits a function exit point. Accomplishing this per-thread debugging facility using registers would require as many registers as the number of exit points. If the number of exit points in a function is more than the number of registers available, then it becomes difficult and complicated to debug the function exit for selective threads using the registers.